﻿using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System;
using System.Windows.Controls;

namespace NopControls
{
    public partial class ColorPicker
    {
        // Events
        public event EventHandler OnColorChanged;

        // Dependency properties
        public static readonly DependencyProperty SelectedColorProperty =
            DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorPicker), null);

        public static readonly DependencyProperty OriginalColorProperty =
            DependencyProperty.Register("OriginalColor", typeof(Color), typeof(ColorPicker), new PropertyMetadata(new PropertyChangedCallback(OnOriginalColorChanged)));

        public Color SelectedColor
        {
            get { return (Color)GetValue(SelectedColorProperty); }
            set
            {
                SetValue(SelectedColorProperty, value);
                if (isLoaded)
                    UpdateCurrentColorFromColor(value);
            }
        }

        public Color OriginalColor
        {
            get { return (Color)GetValue(OriginalColorProperty); }
            set
            {
                SetValue(OriginalColorProperty, value);
            }
        }

        static void OnOriginalColorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ColorPicker picker = obj as ColorPicker;
            picker.OriginalColorView.Fill = new SolidColorBrush(((Color)args.NewValue));
        }

        // Members
        bool HueLevelMouseCaptured;
        bool sampleMouseCaptured;
        double huePos;
        double sampleX;
        double sampleY;
        bool blockUpdate;
        bool isLoaded;

        public ColorPicker()
        {
            InitializeComponent();

#if WINDOWS_PHONE
            SolidColorBrush accentBrush = (SolidColorBrush)Resources["PhoneAccentBrush"];
            LeftHueSelector.Stroke = accentBrush;
            LeftHueSelector.Fill = accentBrush;
            RightHueSelector.Stroke = accentBrush;
            RightHueSelector.Fill = accentBrush;
#endif
        }

        private Color GetColor()
        {
            double yComponent = 1 - (sampleY / ColorPanel.ActualHeight);
            double xComponent = sampleX / ColorPanel.ActualWidth;
            double hueComponent = (huePos / HueLevel.ActualHeight) * 360;

            HSV hsv = new HSV(hueComponent, xComponent, yComponent);

            return hsv.ToColor();
        }

        private void UpdateSatValSelection(bool setCurrentColor)
        {
            SelectorTranslate.X = sampleX - 5;
            SelectorTranslate.Y = sampleY - 5;

            if (setCurrentColor)
                SetCurrentColor(null);
        }

        void SetCurrentColor(HSV? hsv)
        {
            blockUpdate = true;
            Color currColor = GetColor();
            SelectedColorView.Fill = new SolidColorBrush(currColor);

            sliderR.Value = currColor.R;
            sliderG.Value = currColor.G;
            sliderB.Value = currColor.B;

            if (hsv == null)
                hsv = currColor.ToHSV();

            sliderH.Value = hsv.Value.Hue;
            sliderS.Value = hsv.Value.Saturation * 100.0;
            sliderV.Value = hsv.Value.Value * 100.0;

            SetValue(SelectedColorProperty, currColor);
            if (OnColorChanged != null)
                OnColorChanged(this, EventArgs.Empty);

            blockUpdate = false;
        }

        private void UpdateHueSelection(HSV? hsv)
        {
            double pos = huePos / HueLevel.ActualHeight * 255;

            Color color = Tools.GetColorFromPosition(pos);
            ColorPanel.Fill = new SolidColorBrush(color);

            HueSelectorTranslate.Y = huePos - 4;

            SetCurrentColor(hsv);
        }

        void UpdateCurrentColorFromColor(Color color)
        {
            HSV hsv = color.ToHSV();

            UpdateCurrentColorFromHSV(hsv);
        }

        void UpdateCurrentColorFromHSV(HSV hsv)
        {
            Color currColor = GetColor();
            HSV currHsv = currColor.ToHSV();

            if (hsv == currHsv)
                return;

            huePos = (hsv.Hue / 360 * HueLevel.ActualHeight);
            sampleY = (1 - hsv.Value) * ColorPanel.ActualHeight;
            sampleX = hsv.Saturation * ColorPanel.ActualWidth;

            UpdateHueSelection(hsv);
            UpdateSatValSelection(false);
        }

        // Hue level
        private void HueLevel_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            HueLevelMouseCaptured = HueLevel.CaptureMouse();
            DragSliders(0, e.GetPosition((UIElement)sender).Y);
        }

        private void HueLevel_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            HueLevel.ReleaseMouseCapture();
            HueLevelMouseCaptured = false;
        }

        private void HueLevel_MouseMove(object sender, MouseEventArgs e)
        {
            DragSliders(0, e.GetPosition((UIElement)sender).Y);
        }

        // Color panel
        private void ColorPanel_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            sampleMouseCaptured = ColorPanel.CaptureMouse();
            Point pos = e.GetPosition((UIElement)sender);
            DragSliders(pos.X, pos.Y);
        }

        private void ColorPanel_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            ColorPanel.ReleaseMouseCapture();
            sampleMouseCaptured = false;
        }

        private void ColorPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (!sampleMouseCaptured)
                return;

            Point pos = e.GetPosition((UIElement)sender);
            DragSliders(pos.X, pos.Y);
        }

        // Sliders
        private void DragSliders(double x, double y)
        {
            if (HueLevelMouseCaptured)
            {
                if (y < 0)
                    huePos = 0;
                else if (y > HueLevel.ActualHeight)
                    huePos = HueLevel.ActualHeight;
                else
                    huePos = y;
                UpdateHueSelection(null);
            }
            else if (sampleMouseCaptured)
            {
                if (x < 0)
                    sampleX = 0;
                else if (x > ColorPanel.ActualWidth)
                    sampleX = ColorPanel.ActualWidth;
                else
                    sampleX = x;

                if (y < 0)
                    sampleY = 0;
                else if (y > ColorPanel.ActualHeight)
                    sampleY = ColorPanel.ActualHeight;
                else
                    sampleY = y;

                UpdateSatValSelection(true);
            }
        }

        private void sliderR_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromColor(Color.FromArgb(255, (byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value));
        }

        private void sliderG_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromColor(Color.FromArgb(255, (byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value));
        }

        private void sliderB_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromColor(Color.FromArgb(255, (byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value));
        }

        private void sliderH_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromHSV(new HSV(sliderH.Value, sliderS.Value / 100.0, sliderV.Value / 100.0));
        }

        private void sliderS_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromHSV(new HSV(sliderH.Value, sliderS.Value / 100.0, sliderV.Value / 100.0));
        }

        private void sliderV_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (blockUpdate)
                return;
            UpdateCurrentColorFromHSV(new HSV(sliderH.Value, sliderS.Value / 100.0, sliderV.Value / 100.0));
        }

        // Control
        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (!isLoaded)
                return;

            UpdateCurrentColorFromColor(Color.FromArgb(255, (byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value));
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            isLoaded = true;
            UpdateCurrentColorFromColor(SelectedColor);
        }

        private void text_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                sliderR.Focus();
            }
        }
    }
}
